#include "../include/object.h"
#include "../include/inner_object.h"
#include "../include/graphics.h"
#include <vector>
#include <fstream>
using namespace std;

#define INIT_IMG_COUNT 10

vector<Image> img_info[OBJ_TYPE_COUNT];
LinkedList obj_list(true);
LinkedList extra_info(true);
InnerObject score_board[MAX_PLAYERS][MAX_DIGITS];
InnerObject player[MAX_PLAYERS];
int player_count;

//local functions
char type_str[OBJ_TYPE_COUNT][100] = {"BCKGROUND", "MARIO", "PLATFORM", "HARD_BLOCK",
	"FRAGILE_BLOCK", "CLOUD", "FLOWER", "RANDOM_BOX", "MUSHROOM2",
	"POISONED_MUSHROOM", "BULLET", "DIGIT", "TAG"};
int translateType(char *type)
{
	int i;
	for(i = 0; i < OBJ_TYPE_COUNT; i++)
	{
		if(strcmp(type_str[i], type) == 0)
			break;
	}
	if(i == OBJ_TYPE_COUNT)return -1;
	return i;
}

bool loadImageInfo(const char *filename)
{
	ifstream infile;
	infile.open(filename, ios::in);
	if(!infile || infile.bad())return false;

	bool flag = true;
	while(!infile.eof())
	{
		char buf1[100], buf2[100];
		int count, cur_type;
		infile >> buf1 >> buf2 >> count;
		if(strcmp(buf1, "type") == 0 && (cur_type = translateType(buf2)) != -1)
		{
			img_info[cur_type].resize(count);
			for(int j = 0; j < count; j++)
			{
				infile >> img_info[cur_type][j].pos.x >> img_info[cur_type][j].pos.y >> img_info[cur_type][j].size.x >> img_info[cur_type][j].size.y;
				infile.get();
				infile >> buf1;
				img_info[cur_type][j].texture = ggLoadTexture(buf1);
			}
		}
		else
		{
			flag = false;
			break;
		}
	}
	infile.close();
	if(flag)return true;
	else
		return false;
}

extern "C" void objectInit()
{
	for(int i = 0; i < OBJ_TYPE_COUNT; i++)img_info[i].resize(INIT_IMG_COUNT);
	loadImageInfo("img_info.cfg");
}

extern "C" hObject firstObject(iObjectIterator *i)
{
	Node **p = (Node**)i;
	*p = obj_list.getFirst();
	if(*p == 0)return 0;
	else
		return ((InnerObject*)(((*p)->ele) >> 32))->getHObject();
}

extern "C" hObject nextObject(iObjectIterator *i)
{
	Node **p = (Node**)i;

	if(*p == 0)return 0;
	*p = obj_list.getNext(*p);
	if(*p == 0)return 0;
	else
		return ((InnerObject*)(((*p)->ele) >> 32))->getHObject();
}

extern "C" hObject lastObject(iObjectIterator *i)
{
	Node **p = (Node**)i;
	*p = obj_list.getLast();
	if(*p == 0)return 0;
	else
		return ((InnerObject*)(((*p)->ele) >> 32))->getHObject();
}

extern "C" hObject prevObject(iObjectIterator *i)
{
	Node **p = (Node**)i;

	if(*p == 0)return 0;
	*p = obj_list.getPrev(*p);
	if(*p == 0)return 0;
	else
		return ((InnerObject*)(((*p)->ele) >> 32))->getHObject();
}

extern "C" hObject curObject(iObjectIterator *i)
{
	Node **p = (Node**)i;

	if(*p == 0)return 0;
	else
		return ((InnerObject*)(((*p)->ele) >> 32))->getHObject();
}

extern "C" pObject getData(hObject obj)
{
	return ((InnerObject*)(obj >> 32))->getPublicInfo();
}

extern "C" hObject getPlayer(int id)
{
	return player[id].getHObject();
}

extern "C" int getPlayerCount()
{
	return player_count;
}

extern "C" void setPlayerCount(int count)
{
	player_count = count;
}

extern "C" hObject newObject(pObject obj)
{
	InnerObject *o = new InnerObject(*obj);
	return o->getHObject();
}

extern "C" void deleteObject(hObject obj)
{
	if(obj == 0)return;
	delete (InnerObject*)(obj >> 32);
}

extern "C" void addObject(hObject obj)
{
	if(obj == 0)return;
	if(obj_list.find(obj, NULL) !=-1)return;
	obj_list.push_back(obj);
}

extern "C" char findObject(hObject obj)
{
	if(obj == 0)return 0;
	for(int i = 0; i < getPlayerCount(); i++)
		if(obj == getPlayer(i))return 1;
	return obj_list.find(obj, NULL) != -1;
}

extern "C" void removeObject(hObject obj)
{
	if(obj == 0)return;
	obj_list.remove(obj);
}

extern "C" void removeAllObjects()
{
	obj_list.clear();
}

extern "C" const pImage getImage(hObject obj)
{
	if(obj == 0)return 0;
	pObject o = ((InnerObject*)(obj >> 32))->getPublicInfo();
	return &img_info[o->obj_type][o->img_index];
}

extern "C" pImage getImageWithFullAccess(int obj_type, int img_index)
{
	return &img_info[obj_type][img_index];
}

extern "C" int getMarioId(hObject obj)
{
    for(int i = 0; i < getPlayerCount(); i++)
    {
        if(getPlayer(i) == obj)return i;
    }
    return 0;
}

extern "C" hObject getScoreBoard(int player, int digit)
{
	if(player >= MAX_PLAYERS || digit >= MAX_DIGITS)return 0;
	return score_board[player][digit].getHObject();
}

extern "C" void updateScoreBoard(int player, int num)
{
	if(player > MAX_PLAYERS)return;

	char out[MAX_DIGITS];
	sprintf(out, "%03d", num % 1000);
	for(int i = 1; i < MAX_DIGITS; i++)score_board[player][i].getPublicInfo()->img_index = out[i - 1] - '0';
}